package com.example.exam.utils;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.Protocol;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.internal.SkipMd5CheckStrategy;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.example.exam.entity.Base64;
import com.example.exam.mapper.Base64Mapper;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.Objects;

/**
 * @author zhang
 */
@Service
@Log4j2
public class AmazeS3Utils {
    /**
     * 对象存储用户的access key
     */
    @Value("${s3.accessKeyId}")
    private String accessKey;

    /**
     * 对象存储用户的的secret key
     */
    @Value("${s3.secretAccessKey}")
    private String secretKey;

    /**
     * EDS对象存储的地址:对象存储服务的端口号
     */
    @Value("${s3.endpoint}")
    private String endPoint;

    /**
     * EDS对象存储的bucket名称
     */
    @Value("${s3.bucketName}")
    private String bucketName;


    private AmazonS3 amazonS3Client;


    private TransferManager transferManager;

    @PostConstruct
    public void init() {
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        ClientConfiguration clientConfig = new ClientConfiguration();
        clientConfig.setProtocol(Protocol.HTTP);
        clientConfig.setConnectionTimeout(300000);
        clientConfig.setClientExecutionTimeout(300000);
        clientConfig.setConnectionMaxIdleMillis(300000);
        System.setProperty(SkipMd5CheckStrategy.DISABLE_GET_OBJECT_MD5_VALIDATION_PROPERTY, "true");
        // 初始化AmazonS3Client
        this.amazonS3Client = AmazonS3ClientBuilder.standard().
                withClientConfiguration(clientConfig).
                withCredentials(new AWSStaticCredentialsProvider(credentials)).
                withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, null)).
                build();
        this.transferManager = TransferManagerBuilder.standard().withS3Client(amazonS3Client).build();
    }

    /**
     * 流式上传文件到EDS
     *
     * @param keyName     fileName
     * @param inputStream InputStream
     * @return PutObjectResult
     */
    public PutObjectResult streamUpload(String keyName, InputStream inputStream) {
        try {
            //创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            //上传的文件的长度
            metadata.setContentLength(inputStream.available());
            //指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            //指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            //指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            //文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            //如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType("application/octet-stream");
            return amazonS3Client.putObject(bucketName, keyName, inputStream, metadata);
        } catch (IOException e) {
            log.error("文件上传失败。。。。{}", e.getMessage());
            throw new RuntimeException(e);
        } catch (SdkClientException e) {
            throw new RuntimeException(e);
        }
    }

    public InputStream download(String key) {
        log.info("Downloading {} from S3 bucket {}...\n", key, bucketName);
        S3Object object = amazonS3Client.getObject(new GetObjectRequest(bucketName, key));
        return object.getObjectContent();
    }

    /**
     * 创建文件下载的预签名--URL
     *
     * @param keyName 唯一文件标识
     * @return URL
     */
    public URL createSignedUrlForStringGet(String keyName) {
        Date expiration = new Date();
        long expirationNumber = expiration.getTime() + 3600 * 1000;
        expiration.setTime(expirationNumber);
        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, keyName, HttpMethod.GET);
        generatePresignedUrlRequest.setExpiration(expiration);
        return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest);
    }


    @Autowired
    private Base64Mapper base64Mapper;

    @SneakyThrows
    public String uploadImg(MultipartFile file) {
        String fileName;
        byte[] bytes = file.getBytes();
        String base = FileUtils.isOneFile(bytes);
        Base64 base64 = base64Mapper.selectById(base);
        //如果base64为空，说明是第一次上传，否则直接返回文件名
        if (base64 == null) {
            base64 = new Base64();
            base64.setBase64(base);
            base64Mapper.insert(base64);
            fileName = FileUtils.fileNameToUuid(Objects.requireNonNull(file.getOriginalFilename()));
            streamUpload(fileName, file.getInputStream());
        } else {
            fileName = base64.getFileName();
        }
        return fileName;
    }

}
